package com.g0dkar.leet.log;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public final class Log {
	
	private static final String SEPARATOR = " ~ ";
	private static Logger logger = LoggerFactory.getLogger(Log.class);
//	private static Logger logger = new DummyLogger();
	
	private Log() {
		throw new InstantiationError("Esta classe não deve ser instanciada: " + Log.class.getName());
	}
	
	public static void trace(String message, Throwable t) {
		logger.trace(message + SEPARATOR + getCaller(), t);
	}
	
	public static void trace(String padrao, String... args) {
		logger.trace(padrao + SEPARATOR + getCaller(), args);
	}
	
	public static void debug(String message, Throwable t) {
		logger.debug(message + SEPARATOR + getCaller(), t);
	}
	
	public static void debug(String padrao, String... args) {
		logger.debug(padrao + SEPARATOR + getCaller(), args);
	}
	
	public static void info(String message, Throwable t) {
		logger.info(message + SEPARATOR + getCaller(), t);
	}
	
	public static void info(String padrao, String... args) {
		logger.info(padrao + SEPARATOR + getCaller(), args);
	}
	
	public static void warn(String message, Throwable t) {
		logger.warn(message + SEPARATOR + getCaller(), t);
	}
	
	public static void warn(String padrao, String... args) {
		logger.warn(padrao + SEPARATOR + getCaller(), args);
	}
	
	public static void error(String message, Throwable t) {
		logger.error(message + SEPARATOR + getCaller(), t);
	}
	
	public static void error(String padrao, String... args) {
		logger.error(padrao + SEPARATOR + getCaller(), args);
	}
	
	static String getCaller() {
		try {
			StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
			/*
			 * The LEVEL starts with 3 because the stacktrace should look like this:
			 * - 0 Thread.currentThread().getStackTrace()
			 * - 1 JHeatLogger.getCaller()
			 * - 2 JHeatLogger.[trace/debug/info/warn/error]()
			 * - 3 Invoker.logEvent() <-- the desired method to find
			 */
			final int LEVEL = 3;
			/*
			 * This matching is to ignore the method invokers used with reflection [Method.invoke() and its native counterparts]
			 */
			for (int i = LEVEL; i < stackTrace.length; ++i) {
				if (!stackTrace[i].getClassName().matches("(sun|java\\.lang)\\.reflect\\..*")) {
					return stackTrace[i].toString();
				}
			}
		} catch (SecurityException e) {
			return "source not shown because getting thread's stackTrace isn't allowed: " + e;
		}
		return "";
	}
	
}
